using Microsoft.Phone.Controls.Maps.AutomationPeers;
using Microsoft.Phone.Controls.Maps.Core;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Controls;
using System.Windows.Media;
namespace Microsoft.Phone.Controls.Maps
{
	[TemplatePart(Name = "ContentGrid", Type = typeof(Grid))]
	public sealed class MapTileLayer : Control, IProjectable
	{
		internal const string ContentGridElementName = "ContentGrid";
		private const double offsetPixels = 0.75;
		private readonly Collection<MultiScaleImage> msiCollection;
		private readonly MapMode parentMode;
		private readonly TileSourceCollection tileSources;
		private readonly WeakEventListener<MapTileLayer, object, NotifyCollectionChangedEventArgs> weakCollectionListener;
		private readonly WeakEventListener<MapTileLayer, object, TileSourcePropertyChangedEventArgs> weakItemListener;
		private Grid contentGrid;
		private int tileHeight = 256;
		private int tileWidth = 256;
		private bool updated;
		public static readonly DependencyProperty UpSampleLevelDeltaProperty = DependencyProperty.Register("UpSampleLevelDelta", typeof(int), typeof(MapTileLayer), new PropertyMetadata(2147483647));
		public int TileWidth
		{
			get
			{
				return this.tileWidth;
			}
			set
			{
				this.tileWidth = value;
				this.RefreshSource();
			}
		}
		public int TileHeight
		{
			get
			{
				return this.tileHeight;
			}
			set
			{
				this.tileHeight = value;
				this.RefreshSource();
			}
		}
		public TileSourceCollection TileSources
		{
			get
			{
				return this.tileSources;
			}
		}
		public int UpSampleLevelDelta
		{
			get
			{
				return (int)base.GetValue(MapTileLayer.UpSampleLevelDeltaProperty);
			}
			set
			{
				base.SetValue(MapTileLayer.UpSampleLevelDeltaProperty, value);
			}
		}
		internal bool IsDownloading
		{
			get
			{
				using (IEnumerator<UIElement> enumerator = this.contentGrid.get_Children().GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						UIElement current = enumerator.get_Current();
						MultiScaleImage multiScaleImage = current as MultiScaleImage;
						if (multiScaleImage != null && multiScaleImage.get_Visibility() == null && multiScaleImage.get_IsDownloading())
						{
							return true;
						}
					}
				}
				return false;
			}
		}
		internal bool IsIdle
		{
			get
			{
				if (!this.updated)
				{
					return false;
				}
				using (IEnumerator<UIElement> enumerator = this.contentGrid.get_Children().GetEnumerator())
				{
					while (enumerator.MoveNext())
					{
						UIElement current = enumerator.get_Current();
						MultiScaleImage multiScaleImage = current as MultiScaleImage;
						if (multiScaleImage != null && multiScaleImage.get_Visibility() == null && !multiScaleImage.get_IsIdle())
						{
							return false;
						}
					}
				}
				return true;
			}
		}
		public MapBase ParentMap
		{
			get
			{
				IProjectable projectable = base.get_Parent() as IProjectable;
				if (projectable != null)
				{
					return projectable.ParentMap;
				}
				return base.get_Parent() as MapBase;
			}
		}
		private MapMode ParentMode
		{
			get
			{
				if (this.parentMode != null)
				{
					return this.parentMode;
				}
				MapBase parentMap = this.ParentMap;
				if (parentMap == null)
				{
					return null;
				}
				return parentMap.Mode;
			}
		}
		private Size ViewportSize
		{
			get
			{
				Size result;
				if (this.parentMode != null)
				{
					result = this.parentMode.ViewportSize;
				}
				else
				{
					MapBase parentMap = this.ParentMap;
					result = ((parentMap != null) ? parentMap.ViewportSize : new Size(0.0, 0.0));
				}
				return result;
			}
		}
		public MapTileLayer()
		{
			base.set_DefaultStyleKey(typeof(MapTileLayer));
			base.set_IsHitTestVisible(false);
			this.contentGrid = new Grid();
			this.tileSources = new TileSourceCollection();
			this.weakItemListener = new WeakEventListener<MapTileLayer, object, TileSourcePropertyChangedEventArgs>(this);
			this.weakItemListener.OnEventAction = delegate(MapTileLayer instance, object source, TileSourcePropertyChangedEventArgs eventArgs)
			{
				instance.TileSources_ItemPropertyChanged(source, eventArgs);
			};
			this.tileSources.ItemPropertyChanged += new EventHandler<TileSourcePropertyChangedEventArgs>(this.weakItemListener.OnEvent);
			this.weakCollectionListener = new WeakEventListener<MapTileLayer, object, NotifyCollectionChangedEventArgs>(this);
			this.weakCollectionListener.OnEventAction = delegate(MapTileLayer instance, object source, NotifyCollectionChangedEventArgs eventArgs)
			{
				instance.TileSources_CollectionChanged(source, eventArgs);
			};
			this.tileSources.add_CollectionChanged(new NotifyCollectionChangedEventHandler(this.weakCollectionListener.OnEvent));
			this.msiCollection = new Collection<MultiScaleImage>();
		}
		internal MapTileLayer(MapMode mode) : this()
		{
			this.parentMode = mode;
			this.parentMode.ProjectionChanged += new EventHandler<ProjectionChangedEventArgs>(this.ParentMode_ProjectionChanged);
		}
		public override void OnApplyTemplate()
		{
			base.OnApplyTemplate();
			this.contentGrid = (base.GetTemplateChild("ContentGrid") as Grid);
		}
		internal void RefreshSource()
		{
			using (IEnumerator<MultiScaleImage> enumerator = this.msiCollection.GetEnumerator())
			{
				while (enumerator.MoveNext())
				{
					MultiScaleImage current = enumerator.get_Current();
					current.set_Source(new MultiScaleQuadTileSource(this.TileSources, this.TileWidth, this.TileHeight));
				}
			}
			base.InvalidateMeasure();
		}
		public void ProjectionUpdated(ProjectionUpdateLevel updateLevel)
		{
			if (this.parentMode == null)
			{
				base.InvalidateMeasure();
				base.InvalidateArrange();
			}
		}
		protected override Size MeasureOverride(Size availableSize)
		{
			this.UpdateMSI();
			this.contentGrid.Measure(this.ViewportSize);
			return this.ViewportSize;
		}
		private void ParentMode_ProjectionChanged(object sender, ProjectionChangedEventArgs e)
		{
			base.InvalidateMeasure();
			base.InvalidateArrange();
		}
		private MultiScaleImage CreateMSI()
		{
			MultiScaleImage multiScaleImage = new MultiScaleImage();
			multiScaleImage.set_ViewportWidth(1.0);
			multiScaleImage.set_ViewportOrigin(default(Point));
			multiScaleImage.set_UseSprings(false);
			multiScaleImage.set_CacheMode(new BitmapCache());
			multiScaleImage.set_Source(new MultiScaleQuadTileSource(this.TileSources, this.TileWidth, this.TileHeight));
			return multiScaleImage;
		}
		private MultiScaleImage GetMSI(int key)
		{
			MultiScaleImage multiScaleImage;
			if (this.msiCollection.get_Count() <= key)
			{
				multiScaleImage = this.CreateMSI();
				this.msiCollection.Add(multiScaleImage);
			}
			else
			{
				multiScaleImage = this.msiCollection.get_Item(key);
			}
			if (!this.contentGrid.get_Children().Contains(multiScaleImage))
			{
				this.contentGrid.get_Children().Add(multiScaleImage);
			}
			return multiScaleImage;
		}
		private void UpdateMSI()
		{
			FlatMapMode flatMapMode = this.ParentMode as FlatMapMode;
			if (flatMapMode != null)
			{
				this.contentGrid.set_Visibility(0);
				Rect rect = new Rect(flatMapMode.ViewportPointToLogicalPoint(new Point(0.0, 0.0)), flatMapMode.ViewportPointToLogicalPoint(new Point(this.ViewportSize.get_Width(), this.ViewportSize.get_Height())));
				double zoomLevel = flatMapMode.ZoomLevel;
				int num = (int)Math.Floor(zoomLevel);
				double blurFactor = Math.Pow(2.0, zoomLevel - (double)num);
				bool flag = Math.Round(zoomLevel) == zoomLevel;
				bool leftCenter = false;
				bool rightCenter = false;
				if (flag)
				{
					Size size = new Size(rect.get_Width() / this.ViewportSize.get_Width(), rect.get_Height() / this.ViewportSize.get_Height());
					rect.set_X(Math.Round(rect.get_X() / size.get_Width()) * size.get_Width());
					rect.set_Y(Math.Round(rect.get_Y() / size.get_Height()) * size.get_Height());
				}
				double num2 = rect.get_X() - Math.Floor((rect.get_X() + rect.get_Width() / 2.0 + 0.5) / 2.0) * 2.0;
				if (!flag)
				{
					if (0.0 > num2 + rect.get_Width() / 2.0)
					{
						leftCenter = true;
					}
					else
					{
						if (1.0 < num2 + rect.get_Width() / 2.0)
						{
							rightCenter = true;
						}
					}
				}
				int minTileZoomLevel = num - this.UpSampleLevelDelta;
				MultiScaleImage multiScaleImage = this.GetMSI(0);
				((MultiScaleQuadTileSource)multiScaleImage.get_Source()).MinTileZoomLevel = minTileZoomLevel;
				multiScaleImage.set_ViewportWidth(rect.get_Width());
				multiScaleImage.set_ViewportOrigin(new Point(num2, rect.get_Y()));
				multiScaleImage.set_BlurFactor(blurFactor);
				multiScaleImage.set_RenderTransform(MapTileLayer.GetRenderTransform(multiScaleImage, 0, flag, leftCenter, rightCenter));
				int i = 1;
				int num3 = 1;
				while ((double)num3 + num2 < 1.0)
				{
					multiScaleImage = this.GetMSI(i);
					((MultiScaleQuadTileSource)multiScaleImage.get_Source()).MinTileZoomLevel = minTileZoomLevel;
					multiScaleImage.set_ViewportWidth(rect.get_Width());
					multiScaleImage.set_ViewportOrigin(new Point(num2 + (double)num3, rect.get_Y()));
					multiScaleImage.set_BlurFactor(blurFactor);
					multiScaleImage.set_RenderTransform(MapTileLayer.GetRenderTransform(multiScaleImage, -num3, flag, leftCenter, rightCenter));
					i++;
					num3++;
				}
				num3 = 1;
				while ((double)num3 < rect.get_Width() + num2)
				{
					multiScaleImage = this.GetMSI(i);
					((MultiScaleQuadTileSource)multiScaleImage.get_Source()).MinTileZoomLevel = minTileZoomLevel;
					multiScaleImage.set_ViewportWidth(rect.get_Width());
					multiScaleImage.set_ViewportOrigin(new Point(num2 - (double)num3, rect.get_Y()));
					multiScaleImage.set_BlurFactor(blurFactor);
					multiScaleImage.set_RenderTransform(MapTileLayer.GetRenderTransform(multiScaleImage, num3, flag, leftCenter, rightCenter));
					i++;
					num3++;
				}
				while (i < this.msiCollection.get_Count())
				{
					multiScaleImage = this.msiCollection.get_Item(i);
					this.contentGrid.get_Children().Remove(multiScaleImage);
					i++;
				}
			}
			else
			{
				this.contentGrid.set_Visibility(1);
			}
			this.updated = true;
		}
		private static Transform GetRenderTransform(MultiScaleImage msi, int offset, bool atIntegerZoom, bool leftCenter, bool rightCenter)
		{
			TranslateTransform translateTransform = null;
			if (!atIntegerZoom)
			{
				translateTransform = (msi.get_RenderTransform() as TranslateTransform);
				if (translateTransform == null)
				{
					translateTransform = new TranslateTransform();
					msi.set_RenderTransform(translateTransform);
				}
				if (leftCenter)
				{
					translateTransform.set_X((double)(-(double)offset - 1) * 0.75);
				}
				else
				{
					if (rightCenter)
					{
						translateTransform.set_X((double)(-(double)offset + 1) * 0.75);
					}
					else
					{
						translateTransform.set_X((double)(-(double)offset) * 0.75);
					}
				}
			}
			return translateTransform;
		}
		private void TileSources_ItemPropertyChanged(object sender, TileSourcePropertyChangedEventArgs e)
		{
			this.updated = false;
			try
			{
				this.contentGrid.get_Dispatcher().BeginInvoke(delegate
				{
					this.RefreshSource();
				});
			}
			catch (Exception)
			{
			}
		}
		private void TileSources_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
		{
			this.updated = false;
			try
			{
				this.contentGrid.get_Dispatcher().BeginInvoke(delegate
				{
					this.RefreshSource();
				});
			}
			catch (Exception)
			{
			}
		}
		protected override AutomationPeer OnCreateAutomationPeer()
		{
			return new MapTileLayerAutomationPeer(this);
		}
	}
}
